/**
 * 旧库抽离
 * 20220304:[require] to [import]...jordia
 * 20220416:correct camera-controller event listening (start/move cross event) 
 */
import {Raycaster,Vector2} from 'three';

/**
 * 提示点击热区
 *
 @param values {object}
 size:0.5, 尺寸大小
 opacity:1, 不透明度
 color: new Color(0.3, 1, 0), 中心区域颜色
 radius: 1, 外圈半径

 通过material编辑通用材质属性
 通过geometry编辑通用几何属性
 */
export default class CameraRayPicker{
    constructor(cameraController){
        this._init();
        if(cameraController)this.camCtr=cameraController;
    }

    //--------------------------------------对外属性及方法-----------------------------------------

    /**
     * 绑定的对象
     * @returns {*|null}
     */
    get object(){
        return this._object;
    }
    set object(obj3D){
        this._object=obj3D;
    }

    /**
     * 射线检测函数
     * @param func_raycaster_target_return_intersection
     */
    set intersectFunction(func_raycaster_target_return_intersection){
        this._rayFunc=func_raycaster_target_return_intersection;
    }

    /**
     * 射线检测结果处理函数
     * @param func_intersection_return_boolean
     */
    set checkIntersection(func_intersection_return_boolean){
        this._checkFunc=func_intersection_return_boolean;
    }

    /**
     * 设置相机控制（crossEvent用于交互,camera用于设置射线）
     * @param camCtr
     */
    set camCtr(camCtr){
        if(camCtr){
            if(this._camCtr!==null)return;
            this._camCtr=camCtr;
            this._camCtr.startCrossEvent.addEventListener('pointDown',this.onPointDown);
            this._camCtr.moveCrossEvent.addEventListener('pointMove',this.onPointMove);
            this._camCtr.moveCrossEvent.addEventListener('pointUp',this.onPointUp);
            this._camCtr.moveCrossEvent.addEventListener('pointOut',this.onPointOut);
        }else{
            if(this._camCtr===null)return;
            this._camCtr.startCrossEvent.removeEventListener('pointDown',this.onPointDown);
            this._camCtr.moveCrossEvent.removeEventListener('pointMove',this.onPointMove);
            this._camCtr.moveCrossEvent.removeEventListener('pointUp',this.onPointUp);
            this._camCtr.moveCrossEvent.removeEventListener('pointOut',this.onPointOut);
            this._camCtr=null;
        }
    }

    /**
     * 开始回调
     * @param func_bool
     */
    set onStart(func_bool){
        this._startCall=func_bool;
    }

    /**
     * 结束回调
     * @param func_bool
     */
    set onEnd(func_bool){
        this._endCall=func_bool;
    }

    /**
     * 悬停回调
     * @param func_bool
     */
    set onHover(func_bool){
        this._hoverCall=func_bool;
    }

    /**
     * 按下回调
     * @param func_bool
     */
    set onPress(func_bool){
        this._pressCall=func_bool;
    }

    /**
     * 点击回调
     * @param func
     */
    set onClick(func){
        this._clickCall=func;
    }

    /**
     * 设置射线检测区域（当实际区域与相机视口不同时）
     */
    setRect(left,top,width,height){
        if(!this._rect)this._rect={};
        this._rect.left=left;
        this._rect.top=top;
        this._rect.width=width;
        this._rect.height=height;
    }

    /**
     * 设置射线
     * @param pointer
     */
    setRaycaster(pointer){
        let rect = this._rect||this._camCtr.rect;
        let x = (pointer.x - rect.left) / rect.width;
        let y = (pointer.y - rect.top) / rect.height;
        this._pointerVector.set((x * 2) - 1, 1 - (y * 2));
        this._raycaster.setFromCamera(this._pointerVector, this._camCtr.camera);
    }

    /**
     * 销毁
     */
    dispose(){
        this.camCtr=null;
        this._raycaster=null;
        this._pointerVector=null;
        this._isHover=null;
        this._isPress=null;
        this._hoverCall=null;
        this._startCall=null;
        this._endCall=null;
        this._pressCall=null;
        this._clickCall=null;
        this._rect=null;
    }

    //------------------------------------------私有属性及方法-------------------------------------

    _checkObject(){
        if(!this._object)return false;
        if(typeof this._rayFunc!=='function')return false;
        if(!this._object.visible)return false;
        return this._camCtr.camera.layers.test(this._object.layers);
    }
    _init(){
        this._initVariable();
        this._initEventBind();
    }
    _initEventBind(){
        this.onPointMove=(e)=>{
            if(!this._checkObject())return;
            this.setRaycaster(e.isMouse ? new Vector2(e.clientX, e.clientY) : new Vector2(e.touches[0].clientX, e.touches[0].clientY));
            let intersection = this._rayFunc(this._raycaster,this._object);
            let _isHover=this._checkFunc(intersection);
            if(this._isHover===_isHover)return;
            this._isHover=_isHover;
            this._hoverCall(this._isHover);
        };
        this.onPointDown=(e)=>{
            if(!this._checkObject())return;
            this.setRaycaster(e.isMouse ? new Vector2(e.clientX, e.clientY) : new Vector2(e.touches[0].clientX, e.touches[0].clientY));
            let intersection = this._rayFunc(this._raycaster,this._object);
            let _isPress=this._checkFunc(intersection);
            if(_isPress)this._startCall();
            if(this._isPress===_isPress)return;
            this._isPress=_isPress;
            this._pressCall(this._isPress);
        };
        this.onPointOut=()=>{
            if(!this._checkObject())return;
            if(this._isPress) {
                this._isPress = false;
                this._pressCall(this._isPress);
                this._endCall();
            }
            if(this._isHover){
                this._isHover=false;
                this._hoverCall(this._isHover);
            }
        };
        this.onPointUp=(e)=> {
            if(!this._checkObject())return;
            if (!this._isPress)return;
            this._endCall();
            this._isPress = false;
            this._pressCall(this._isPress);
            this.setRaycaster(e.isMouse ? new Vector2(e.clientX, e.clientY) : new Vector2(e.changedTouches[0].clientX, e.changedTouches[0].clientY));
            let intersection = this._rayFunc(this._raycaster,this._object);
            if (!this._checkFunc(intersection))return;
            this._clickCall();
        };
    }
    _initVariable(){
        this._object=null;
        this._camCtr=null;
        this._raycaster=new Raycaster();
        this._pointerVector=new Vector2();
        this._isHover=false;
        this._isPress=false;
        this._rect=null;
        this._rayFunc=(caster,target)=>{return caster.intersectObject(target, false);};
        this._checkFunc=(result)=>{return result.length>0};
        this._startCall=()=>{};
        this._endCall=()=>{};
        this._hoverCall=()=>{};
        this._pressCall=()=>{};
        this._clickCall=()=>{};
    }
}
